/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.function.Function;

class GlobalConfig {
    public static final int BASE_VALUE = 1000;
    public static final int BIT_BINARY_NUMBER_3 = 3;
    public static final int NUMBER_14 = 14;
    public static final int NUMBER_6 = 6;
    public static final int BINARY_2 = 2;
    public static final int BINARY_5 = 5;
    public static final int LOOP_I_MAX_500 = 500;
    public static final int LOOP_Y_MAX_256 = 256;
    public static final int EXECUTION_MAX_NUMBER_80 = 80;

    public static boolean inDebug = false;

    public static void log(String str) {
        if (inDebug) {
            System.out.println(str);
        }
    }

    public static double currentTimestamp13() {
        return (double) System.nanoTime() / 1_000_000;
    }

    public int result = 0;

    // 1 op = 6 ANDs, 3 SHRs, 3 SHLs, 4 assigns, 2 ADDs
    // O(1)
    public static int fast3bitLookup(int b) {
        int c1 = 0; // 0b1110 1001 1001 0100;
        int bi3b = 0xe994; // 3 2 2 1  2 1 1 0
        c1 = BIT_BINARY_NUMBER_3 & (bi3b >> ((b << 1) & NUMBER_14));
        c1 += BIT_BINARY_NUMBER_3 & (bi3b >> ((b >> BINARY_2) & NUMBER_14));
        c1 += BIT_BINARY_NUMBER_3 & (bi3b >> ((b >> BINARY_5) & NUMBER_6));
        return c1;
          /*
            lir4,0xE994; 9 instructions, no memory access, minimal register dependence, 6 shifts, 2 adds, 1 inline assign
            rlwinmr5,r3,1,28,30;
            rlwinmr6,r3,30,28,30;
            rlwinmr7,r3,27,29,30;
            rlwnmr8,r4,r5,30,31;
            rlwnmr9,r4,r6,30,31;
            rlwnmr10,r4,r7,30,31;
            addr3,r8,r9;
            addr3,r3,r10;
            */
    }

    public static int timeFunc(Function<Integer, Integer> func1) {
        int x = 0;
        int y = 0;
        int t = 0;
        int sum = 0;
        for (int i = 0; i < LOOP_I_MAX_500; i++) {
            for (y = 0; y < LOOP_Y_MAX_256; y++) {
                sum += func1.apply(y);
            }
        }
        return sum;
    }
}

/*
 * @State
 * @Tags Jetstream2
 */
class Benchmark {
    /*
     * @Benchmark
     */
    public static void run() {
        int sum = GlobalConfig.timeFunc(GlobalConfig::fast3bitLookup);
        int expected = 512000;
        if (sum != expected) {
            throw new Error("ERROR: bad result: expected " + expected + " but got " + sum);
        }
    }

    public static void main(String[] args) {
        double startTime = GlobalConfig.currentTimestamp13();
        Benchmark benchmark = new Benchmark();
        for (int i = 0; i < GlobalConfig.EXECUTION_MAX_NUMBER_80; i++) {
            double startTimeInLoop = GlobalConfig.currentTimestamp13();
            benchmark.run();
            double endTimeInLoop = GlobalConfig.currentTimestamp13();
//            GlobalConfig.log("bitops-3bit-bits-in-byte: ms = " + (endTimeInLoop - startTimeInLoop) + " i= " + i);
        }
        double endTime = GlobalConfig.currentTimestamp13();
        System.out.println("bitops-3bit-bits-in-byte: ms = " + (endTime - startTime));
    }
}
